﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace MassPokerTool.Infrastructure.Extensions
{
    public static class BitmapExtensions
    {
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count);

        public static Bitmap CropImage(this Bitmap source, Rectangle area)
        {
            var bmp = new Bitmap(area.Width, area.Height);
            return source.Clone(area, bmp.PixelFormat);
        }

        public static bool CompareMemCmp(this Bitmap b1, Bitmap b2)
        {
            if ((b1 == null) || (b2 == null))
                return false;
            if (b1.Size != b2.Size)
                return false;
            var bd1 = b1.LockBits(new Rectangle(new Point(0, 0), b1.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            var bd2 = b2.LockBits(new Rectangle(new Point(0, 0), b2.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            try
            {
                var length1 = bd1.Stride * bd1.Height;
                var length2 = bd2.Stride * bd2.Height;

                var bytes1 = new byte[length1];
                var bytes2 = new byte[length2];

                var bd1Scan0 = bd1.Scan0;
                var bd2Scan0 = bd2.Scan0;
                Marshal.Copy(bd1Scan0, bytes1, 0, length1);
                Marshal.Copy(bd2Scan0, bytes2, 0, length2);

                return memcmp(bytes1, bytes2, new UIntPtr((uint)length1)) == 0;
            }
            finally
            {
                b1.UnlockBits(bd1);
                b2.UnlockBits(bd2);
            }
        }

        public static bool BlackAndWhite(this Bitmap b, bool flag)
        {
            // GDI+ still lies to us - the return format is BGR, NOT RGB
            var bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            var stride = bmData.Stride;
            var scan0 = bmData.Scan0;
            const int threshold = 200;

            try
            {
                unsafe
                {
                    var p = (byte*)(void*)scan0;

                    var nOffset = stride - b.Width * 4;

                    for (var y = 0; y < b.Height; ++y)
                    {
                        for (var x = 0; x < b.Width; ++x)
                        {
                            var blue = p[0];
                            var green = p[1];
                            var red = p[2];

                            var binary = (byte)(.299 * red + .587 * green + .114 * blue);

                            if (binary < threshold && flag)
                                p[0] = p[1] = p[2] = 0;
                            else if (binary >= threshold && flag)
                                p[0] = p[1] = p[2] = 255;
                            else if (binary < threshold && !flag)
                                p[0] = p[1] = p[2] = 255;
                            else
                                p[0] = p[1] = p[2] = 0;
                            p[3] = 255; // set alpha channel
                            p += 4;
                        }
                        p += nOffset;
                    }
                }
            }
            finally
            {
                b.UnlockBits(bmData);
            }
            return true;
        }
    }
}
